package com.lh.spring.ioc;

import com.lh.spring.annotation.ioc.Autowired;
import com.lh.spring.annotation.ioc.Component;
import com.lh.spring.annotation.aop.Lazy;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import static com.lh.spring.ioc.ApplicationClass.enumToCase;

/**
 * @Description 用于创建bean的工厂对象
 * @Version 1.0.0
 * @Date 2024/1/14 14:37
 * @Created by LiuHua
 * @Path com.lh.spring.ioc
 */
@Component
public class BeanFactory {
    /**
     * ioc容器用于存放bean的实例化对象
     */
    public static final ConcurrentHashMap<String, Object> iocPool=new ConcurrentHashMap<>();
    /**
     * 存储正在创建中的bean的对象(用于打破依赖循环)
     */
    private static final HashMap<String,Object> earlyIocPool=new HashMap<>();
    private static final HashSet<String> creatingBeanList=new HashSet<>();

    /**
     * 根据bean的名称获取bean的实例对象
     */
    public Object getBean(String beanName){
        return iocPool.get(beanName);
    }
    public Object getBeanType(Class clazz){
        Object o1 = iocPool.values().stream().filter(o -> o.getClass() == clazz).findFirst().orElse(null);
        return o1;
    }

    /**
     * 根据beanDefinition去创建bean对象,并放入ioc容器中
     * @param beanDefinition bean的描述对象
     * @return bean创建是否成功
     */
    public Boolean foundBean(BeanDefinition beanDefinition){
        try {
            //当前beanName是否已经存在
            String beanName = enumToCase.myBeanName(beanDefinition.getBeanName());
            if (!Objects.isNull(iocPool.get(beanName))) {
                new RuntimeException(beanName+"===>BeanName重复,无法创建");
                return false;
            }
            //存储当前正在创建的bean
            creatingBeanList.add(beanName);
            //todo
            // bean的创建
            creatingBean(beanDefinition, beanName);
            //当前bean创建完成删除earlyIocPool中的bean对象
            creatingBeanList.remove(beanName);
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    private void creatingBean(BeanDefinition beanDefinition, String beanName) throws InstantiationException, IllegalAccessException {
        //1.bean的实例化
        Object o = beanDefinition.getClazz().newInstance();
        //2.injection依赖注入
        Object bean=injection(o);
        //3.TODO AOP
        //4.TODO initBean:bean的初始化
        //5.放入ioc容器（单例池中）
        iocPool.put(beanName,bean);
    }

    /**
     * 依赖注入
     * @param o
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private Object injection(Object o) throws IllegalAccessException, InstantiationException {
        //从iocPool中获取
        //防止正在创建中的bean覆盖的已经创建好的bean
        String beanName = enumToCase.myBeanName(o.getClass().getSimpleName());
        if (iocPool.containsKey(beanName)){
            o=iocPool.get(beanName);
        }
        Class<?> clazz = o.getClass();
        //获取所有字段
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            //开启暴力反射
            field.setAccessible(true);
            //该字段是否需要依赖注入
            o = isAutowired(o, field);
        }
        return o;
    }

    /**
     * 该字段是否需要依赖注入
     * @param o
     * @param field
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private Object isAutowired(Object o, Field field) throws IllegalAccessException, InstantiationException {

        if(field.isAnnotationPresent(Autowired.class)){
            o=isLazy(o,field);
            //从单例池中获取
            String name = enumToCase.myBeanName(field.getName());
            Object o1 = iocPool.get(name);
            if (!Objects.isNull(o1)){
                field.set(o,o1);
            }else{
                //从二级缓存中获取
                if (earlyIocPool.containsKey(name)){
                    field.set(o,earlyIocPool.get(name));
                    //删除二级缓存
                }else {
                    //判断当前需要的bean是否正在创建中
                    isCreatingBean(field);
                    foundBean(new BeanDefinition(field.getType(), name));
                    o =injection(o);
                }
            }
        }
        return o;
    }

    private Object isLazy(Object o, Field field) {
        if (field.isAnnotationPresent(Lazy.class)){
            //todo 创建代理对象到iocPool中？（他们之间靠什么关联）
        }
        return o;
    }

    /**
     * 判断当前需要的bean是否正在创建中
     * @param field
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static void isCreatingBean(Field field) throws InstantiationException, IllegalAccessException {
        String beanName = enumToCase.myBeanName(field.getName());
        if (creatingBeanList.contains(beanName)){
            //提前创建完成放入iocPool中
            //TODO 判断是否需要AOP
            if (isAOP(field)){

            }else {
                Object earlyBean = field.getType().newInstance();
                earlyIocPool.put(beanName,earlyBean);
            }
        }
    }

    private static boolean isAOP(Field field) {
        return false;
    }

    public Boolean instanceBean(Object bean,String beanName){
        if (!Objects.isNull(iocPool.get(beanName))){
            return false;
        }
        iocPool.put(beanName,bean);
        return true;
    }
}
